/**
 * 
 */
package cen5501c.common;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;

/**
 * FILE-LIST Issued in response to a LISTFILES request. (NOTE: the client can
 * wait on this response by the server in a recv() or select() system call). The
 * server responds with the number of files known and a record describing each
 * file. The number of file records is included in the arguments field. The
 * actual entries follow. Entries are of the following form: [name of
 * file],[MD5],[creation-time],[startoffset],[endoffset]\n
 * 
 * NOTE: Timestamps, such as used in the [creation-time] field are as specified
 * in RFC822, and, for example, the linux "date -R" command will provide this in
 * the appropriate format. The ASCII encoding of the MD5 signature is simply the
 * 32 character hexadecimal representation of the 128-bit MD5 hash of the entire
 * file as is used in the FILE-CONTENT operation. File names may not contain the
 * tab character, carriage return, or newline characters.
 * 
 * Example: <FILE-LIST,5,"Thu, 14 Feb 2002 23:37:03 -0800">\n
 * file1.txt,c4d338af8376a5b2e418434b03a8dc0e,"16 Sep 2003 19:17:53 GMT",0,32\n
 * file2.exe,e48da1acea1375e38b6b0879fc48611f,"16 Sep 2003 19:15:51 GMT",0,920\n
 * file5.mp3,52942b3180f1f1c7dc4a449fc5125bb4,"16 Sep 2003 19:20:12 GMT",0,98\n
 * paper.pdf,a433dccc9a58abd8b688f23ee2cac2fa,"13 Oct 2003 13:47:14 GMT",0,22\n
 * 
 * @author Jiangyan Xu
 * 
 */
public class FileListCmd extends CmdBase {

	public static final String OPERATION = "FILE-LIST";
	private int numFile;
	private Date responseDate;
	private List<FileListLine> fileListLines;

	/**
	 * @param args
	 * @throws Exception
	 */
	public FileListCmd(List<String> args) throws Exception {
		super(args);
	}
	
	public FileListCmd(int numFile, Date responseDate, List<FileListLine> fileListLines) {
		this.numFile = numFile;
		this.responseDate = responseDate;
		this.fileListLines = fileListLines;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cen5501c.common.CmdBase#fillArgs(java.util.List)
	 */
	@Override
	protected void fillArgs(List<String> args) throws ParseException {
		if (fileListLines == null) {
			fileListLines = new ArrayList<FileListLine>();
		}
		numFile = Integer.parseInt(args.get(0));
		responseDate = CommonUtil.getDateFromRfc822String(args.get(1));
		String[] lines = args.get(2).split("\n");
		for (String line : lines) {
			FileListLine fl = new FileListLine(line);
			fileListLines.add(fl);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cen5501c.common.CmdBase#getArgList()
	 */
	@Override
	public List<String> getArgList() {
		List<String> ret = new ArrayList<String>();
		ret.add(Integer.toString(numFile));
		ret.add(CommonUtil.getDateAsRfc822String(responseDate));
		StringBuilder sb = new StringBuilder();
		for (FileListLine line : fileListLines) {
			sb.append(line.ToString());
		}
		ret.add(sb.toString());
		return ret;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cen5501c.common.CmdBase#getOperation()
	 */
	@Override
	public String getOperation() {
		return OPERATION;
	}

	public static class FileListLine {
		private String filename;
		private String md5;
		private Date creationTime;
		private int startOffset;
		private int endOffset;

		/**
		 * @param filename
		 * @param md5
		 * @param creationTime
		 * @param startOffset
		 * @param endOffset
		 */
		public FileListLine(String filename, String md5, Date creationTime,
				int startOffset, int endOffset) {
			fillArgs(filename, md5, creationTime, startOffset, endOffset);
		}

		/**
		 * @param filename
		 * @param md5
		 * @param creationTime
		 * @param startOffset
		 * @param endOffset
		 */
		private void fillArgs(String filename, String md5, Date creationTime,
				int startOffset, int endOffset) {
			this.filename = filename;
			this.md5 = md5;
			this.creationTime = creationTime;
			this.startOffset = startOffset;
			this.endOffset = endOffset;
		}

		public FileListLine(String fileListLine) throws ParseException {
			if (fileListLine.endsWith("\n")) {
				// trims the end-line character
				fileListLine = fileListLine.substring(0,
						fileListLine.length() - 1);
			}
			String[] args = fileListLine.split(",");

			fillArgs(args[0], args[1], CommonUtil
					.getDateFromRfc822String(args[2]), Integer
					.parseInt(args[3]), Integer.parseInt(args[4]));
		}

		private List<String> getArgList() {
			List<String> ret = new ArrayList<String>();
			ret.add(filename);
			ret.add(md5);
			ret.add(CommonUtil.getDateAsRfc822String(creationTime));
			ret.add(Integer.toString(startOffset));
			ret.add(Integer.toString(endOffset));
			return ret;
		}

		/**
		 * Returns String representation as in the specification. Ends with
		 * '\n'.
		 */
		public String ToString() {
			List<String> arg_list = getArgList();
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < arg_list.size(); i++) {
				if (i != 0) {
					sb.append(',');
				}
				sb.append(arg_list.get(i));
			}
			sb.append('\n');
			return sb.toString();
		}

		/**
		 * @return the filename
		 */
		public String getFilename() {
			return filename;
		}

		/**
		 * @param filename
		 *            the filename to set
		 */
		public void setFilename(String filename) {
			this.filename = filename;
		}

		/**
		 * @return the md5
		 */
		public String getMd5() {
			return md5;
		}

		/**
		 * @param md5
		 *            the md5 to set
		 */
		public void setMd5(String md5) {
			this.md5 = md5;
		}

		/**
		 * @return the creationTime
		 */
		public Date getCreationTime() {
			return creationTime;
		}

		/**
		 * @param creationTime
		 *            the creationTime to set
		 */
		public void setCreationTime(Date creationTime) {
			this.creationTime = creationTime;
		}

		/**
		 * @return the startOffset
		 */
		public int getStartOffset() {
			return startOffset;
		}

		/**
		 * @param startOffset
		 *            the startOffset to set
		 */
		public void setStartOffset(int startOffset) {
			this.startOffset = startOffset;
		}

		/**
		 * @return the endOffset
		 */
		public int getEndOffset() {
			return endOffset;
		}

		/**
		 * @param endOffset
		 *            the endOffset to set
		 */
		public void setEndOffset(int endOffset) {
			this.endOffset = endOffset;
		}
	}

}
